package fi.tikesos.validator.jena.rdfa;

import java.util.HashMap;
import java.util.Map;

import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ReifiedStatement;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;

import fi.tikesos.rdfa.core.datatype.Component;
import fi.tikesos.rdfa.core.datatype.Language;
import fi.tikesos.rdfa.core.parser.sax.SAXLocation;
import fi.tikesos.rdfa.core.triple.TripleSink;

/**
 * @author ssakorho
 * 
 */
public class JenaTripleSink implements TripleSink {
	private Model model;
	private Map<String, Resource> nodeMap;
	private Property positionStatement;

	/**
	 * @param model
	 */
	public JenaTripleSink(Model model) {
		this.model = model;
		this.nodeMap = new HashMap<String, Resource>();
		positionStatement = model
				.createProperty("http://sosmeta.fi#PositionStatement");
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see fi.tikesos.rdfa.TripleSink#generateTriple(fi.tikesos.rdfa.LString,
	 *      fi.tikesos.rdfa.LString, fi.tikesos.rdfa.LString)
	 */
	@Override
	public void generateTriple(Component subject, Component predicate,
			Component object) {
		Resource s = createResource(subject.getValue());
		Property p = model.createProperty(predicate.getValue());
		Resource o = createResource(object.getValue());
		Statement st = model.createStatement(s, p, o);
		ReifiedStatement rt = model.createReifiedStatement(st);
		if (subject.getLocation() != null && predicate.getLocation() != null
				&& object.getLocation() != null) {
			rt.addLiteral(
					positionStatement,
					((SAXLocation) subject.getLocation()).getLine()
							+ ":"
							+ ((SAXLocation) subject.getLocation()).getColumn()
							+ "->"
							+ ((SAXLocation) predicate.getLocation()).getLine()
							+ ":"
							+ ((SAXLocation) predicate.getLocation())
									.getColumn() + "->"
							+ ((SAXLocation) object.getLocation()).getLine()
							+ ":"
							+ ((SAXLocation) object.getLocation()).getColumn());
		} else {
			rt.addLiteral(positionStatement, "Unknown position!");
		}
		model.add(st);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see fi.tikesos.rdfa.TripleSink#generateTripleLiteral(fi.tikesos.rdfa.LString,
	 *      fi.tikesos.rdfa.LString, fi.tikesos.rdfa.LString,
	 *      fi.tikesos.rdfa.LString, fi.tikesos.rdfa.LString)
	 */
	@Override
	public void generateTripleLiteral(Component subject, Component predicate,
			fi.tikesos.rdfa.core.datatype.Literal literal, Language language,
			Component datatype) {
		Resource s = createResource(subject.getValue());
		Property p = model.createProperty(predicate.getValue());
		Literal o;
		if (datatype != null) {
			o = model.createTypedLiteral(literal.getValue(),
					datatype.getValue());
		} else if (language != null) {
			o = model.createLiteral(literal.getValue(), language.getValue());
		} else {
			o = model.createLiteral(literal.getValue());
		}
		Statement st = model.createStatement(s, p, o);
		ReifiedStatement rt = model.createReifiedStatement(st);
		if (subject.getLocation() != null && predicate.getLocation() != null
				&& literal.getLocation() != null) {
			rt.addLiteral(
					positionStatement,
					"S["
							+ ((SAXLocation) subject.getLocation()).getLine()
							+ ":"
							+ ((SAXLocation) subject.getLocation()).getColumn()
							+ "] -> P["
							+ ((SAXLocation) predicate.getLocation()).getLine()
							+ ":"
							+ ((SAXLocation) predicate.getLocation())
									.getColumn() + "] -> O["
							+ ((SAXLocation) literal.getLocation()).getLine()
							+ ":"
							+ ((SAXLocation) literal.getLocation()).getColumn()
							+ "]");
		} else {
			rt.addLiteral(positionStatement, "Unknown position!");
		}
		model.add(st);
	}

	/**
	 * @param URI
	 * @return
	 */
	private Resource createResource(String URI) {
		Resource resource = null;
		if (URI.startsWith("_:") == true) {
			// Anonymous
			resource = nodeMap.get(URI);
			if (resource == null) {
				resource = model.createResource();
				nodeMap.put(URI, resource);
			}
		} else {
			// Named
			resource = model.createResource(URI);
		}
		return resource;
	}

	@Override
	public void startRelativeTripleCaching() {
		// TODO !!!
	}

	@Override
	public void stopRelativeTripleCaching() {
		// TODO !!!
	}

	@Override
	public void generateTriple(String subject, String predicate, String object) {
		// TODO ERROR handling
	}

	@Override
	public void generateTripleLiteral(String subject, String predicate,
			String lexical, String language, String datatype) {
		// TODO ERROR handling
	}
}
